package orders

import (
	"cloud_android_backend/pkg/config"
	"cloud_android_backend/pkg/models/orders"
	"cloud_android_backend/pkg/models/products"
	"cloud_android_backend/pkg/models/resources"
	"cloud_android_backend/pkg/models/users"
	payment2 "cloud_android_backend/pkg/modules/payment"
	"fmt"
	"github.com/golang/glog"
	"github.com/jinzhu/gorm"
	"modules.tenxcloud.com/common/composite"
	"os"
	"time"
)

func init() {
	//go DetectOrderExpire()
	go func() {
		ticker := time.NewTicker(time.Minute * 1)
		for _ = range ticker.C {
			DetectOrderExpire()
		}
	}()
}

type CreateInstanceOrderReq struct {
	CreateOrderReq
	//InstanceId     int64  `json:"instance_id"`
	Quantity         int    `json:"quantity"`
	ProductId        int    `json:"product_id"`
	PackageId        int    `json:"package_id"`
	AutoRenew        bool   `json:"auto_renew"`
	AndroidVersion   string `json:"android_version"`
	RealPhoneModelId int64  `json:"real_phone_model_id"`
	ProxyId          int    `json:"proxy_id"`
}

func CreateInstanceOrderAndPay(params CreateInstanceOrderReq, userId string) (CreateOrderResp, error) {
	var Response CreateOrderResp
	if params.PaymentSource != "wechat" &&
		params.PaymentSource != "alipay" &&
		params.PaymentSource != "balance" &&
		params.PaymentSource != "trial" {
		return Response, fmt.Errorf("payment source not support")
	}
	db, err := composite.Database.GetOrm()
	if err != nil {
		glog.Errorf("get orm failed, error %v", err)
		return Response, err
	}
	if params.PaymentSource == "trial" {
		params.ProductId = 5
		params.PackageId = 20
		params.Quantity = 1
	}
	ProductModel := products.Products{Id: params.ProductId}
	err = ProductModel.GetById(db)
	if err != nil {
		return Response, err
	}
	orderUnpaidModel := orders.Orders{}
	orderUnpaid, err := orderUnpaidModel.GetOrderByStatusAndUserIdAndCatId(db, int(orders.OrderStatus_Pending), userId, ProductModel.CatId)
	if err != nil {
		glog.Errorf("get order failed, %s", err)
		if !gorm.IsRecordNotFoundError(err) {
			return Response, err
		}
	}
	if orderUnpaid.Id > 0 {
		return Response, fmt.Errorf("存在同型号未支付的订单！请先完成支付")
	}
	UserModel := &users.User{UserID: userId}
	err = UserModel.GetByUserId(db)
	if err != nil {
		return Response, err
	}
	if UserModel.UsedTrialCoupon == 1 && params.PaymentSource == "trial" {
		return Response, fmt.Errorf(" trial coupon used")
	}
	orderGenerator := NewBaseOrderGenerator("PURCHES")
	tradeNo := orderGenerator.Generate()
	ProductPackageInfo := products.ProductPackages{Id: params.PackageId}
	err = ProductPackageInfo.GetById(db)
	if err != nil {
		glog.Errorf("get product package info failed:err %v", err)
		return Response, err
	}
	Amount := ProductPackageInfo.Price * float64(params.Quantity)
	order := &orders.Orders{
		TradeNo:       tradeNo,
		Amount:        Amount,
		Remark:        params.Remark,
		TransType:     int(orders.TransType_Recharge),
		UserId:        userId,
		Status:        int(orders.OrderStatus_Pending),
		CreatedAt:     time.Now(),
		UpdatedAt:     time.Now(),
		PaymentSource: params.PaymentSource,
		ClientIp:      params.ClientIp,
		DeviceInfo:    params.DeviceInfo,
		OrderType:     int(orders.OrderTypeInstance),
		ProductId:     params.ProductId,
		PackageId:     params.PackageId,
		//OrderType: int(orders.OrderStatus_Pending),
		Quantity: params.Quantity,
	}
	err = db.Transaction(func(tx *gorm.DB) error {

		err = order.Create(tx)
		if err != nil {
			glog.Errorf("create order failed:err %v", err)
			return err
		}
		instanceModel := resources.Instances{}
		InstanceList, err := instanceModel.GetByCatIdAndStatusForUpdate(tx, ProductModel.CatId, resources.InstanceStatus_NotSold)
		if err != nil {
			glog.Errorf("get instance failed:err %v", err)
			return err
		}
		if len(InstanceList) < params.Quantity {
			glog.Errorf("instance not enough")
			return fmt.Errorf("库存不足！")
		}
		for i := 0; i < params.Quantity; i++ {

			instanceUses := resources.InstanceUses{
				//InstanceId: params.InstanceId,
				InstanceId: InstanceList[i].Id,
				OrderId:    order.Id,
				StartTime:  time.Now(),
				ExpireTime: time.Now().Add(time.Duration(ProductPackageInfo.Duration) * time.Hour * 24),
				Status:     int(resources.InstanceUseStatusPending),
				UserId:     userId,
				Image:      "android/redroid",
				ImageTag:   params.AndroidVersion,
			}
			err = instanceUses.Create(tx)
			if err != nil {
				glog.Errorf("create instance use failed:err %v", err)
				return err
			}
			instanceModel1 := &InstanceList[i]
			instanceModel1.ProductId = params.ProductId
			instanceModel1.Status = int(resources.InstanceStatus_Sold)
			instanceModel1.AdiTemplateId = params.RealPhoneModelId
			if ProductModel.Type == 1 {
				instanceModel1.IsRealPhone = 0
			} else {
				instanceModel1.IsRealPhone = 1
			}

			err = instanceModel1.UpdatePartFields(tx, map[string]interface{}{
				"status":          int(resources.InstanceStatus_Sold),
				"adi_template_id": params.RealPhoneModelId,
				"is_real_phone":   instanceModel1.IsRealPhone,
			})
		}

		return nil
	})
	if err != nil {
		glog.Errorf("transaction failed:err %v", err)
		return Response, err
	}
	if config.Config == nil {
		config.InitConfig()
	}
	Config := config.Config
	domain := os.Getenv("DOMAIN")
	if domain == "" {
		domain = "https://clp.jtcloud.icu"
	}
	var payment payment2.UniCreateOrder
	switch params.PaymentSource {
	case "wechat":
		payment = &payment2.WechatPay{
			Amount:          Amount * 100,
			Description:     "购买云机",
			OutTradeNo:      tradeNo,
			Remark:          params.Remark,
			WechatPayConfig: Config.WechatPay,
		}
	case "alipay":
		payment = &payment2.Alipay{
			Amount:      Amount,
			Description: "购买云机",
			OutTradeNo:  tradeNo,
			Remark:      params.Remark,
			Subject:     "云机购买",
			Url:         domain + "/purches",
		}
	case "balance":
		payment = &payment2.Balance{
			Amount:  Amount,
			OrderId: order.Id,
			UserId:  userId,
		}
	case "trial":
		payment = &payment2.Trial{
			Amount:  Amount,
			OrderId: order.Id,
			UserId:  userId,
		}
	}
	fmt.Println("payment:", payment)
	result, err := payment.Payment()
	if err != nil {
		glog.Errorf("payment failed:err %v", err)
		return Response, err
	}
	resultType := payment.GetResultType()
	Response = CreateOrderResp{
		Data:       result,
		ResultType: string(resultType),
		TradeNo:    tradeNo,
		OrderId:    order.Id,
	}

	return Response, nil
}

func DetectOrderExpire() {
	glog.Info("start detect order expire !")
	db, err := composite.Database.GetOrm()
	if err != nil {
		glog.Errorf("get db failed:err %v", err)
		return
	}
	glog.Info("detect order expire db:%#v", db)
	ordersModel := &orders.Orders{}
	ordersList, err := ordersModel.GetListPendingAndExpire(db)
	if err != nil {
		glog.Errorf("get orders failed:err %v", err)
	}
	for _, order := range ordersList {
		err := db.Transaction(func(tx *gorm.DB) error {
			orderModel := orders.Orders{Id: order.Id}
			if err := orderModel.GetByIdForUpdate(tx); err != nil {
				glog.Errorf("get order failed:err %v", err)
				return err
			}
			orderModel.Status = int(orders.OrderStatus_Cancel)
			orderModel.UpdatedAt = time.Now()
			if err := orderModel.Update(tx); err != nil {
				glog.Errorf("update order failed:err %v", err)
			}
			if order.OrderType == int(orders.OrderTypeInstance) {
				instanceUsingModel := resources.InstanceUses{OrderId: orderModel.Id}
				err := instanceUsingModel.GetByOrderIdWithInstance(tx)
				if err != nil {
					if err == gorm.ErrRecordNotFound {
						return nil
					}
					glog.Errorf("get instance use failed:err %v", err)
					return err
				}
				instanceModel := instanceUsingModel.Instances
				instanceModel.Status = int(resources.InstanceStatus_NotSold)
				err = instanceModel.UpdatePartFields(tx, map[string]interface{}{"status": int(resources.InstanceStatus_NotSold)})
				if err != nil {
					glog.Errorf("update instance failed:err %v", err)
					return err
				}
			}

			return nil
		})
		if err != nil {
			glog.Errorf("transaction failed:err %v", err)
		}
	}
	glog.Info("detect order expire done")
}

type RenewInstanceReq struct {
	InstanceUseId []int64 `json:"instance_use_ids"`
	PackageId     int     `json:"package_id"`
	AutoRenew     bool    `json:"auto_renew"`
	PaymentSource string  `json:"payment_source"`
	ClientIp      string  `json:"client_ip"`
	DeviceInfo    string  `json:"device_info"`
}

func RenewInstance(params RenewInstanceReq, userId string) (CreateOrderResp, error) {
	var response CreateOrderResp
	db, err := composite.Database.GetOrm()
	if err != nil {
		glog.Errorf("get db failed:err %v", err)
		return response, err
	}

	instanceUseIds := params.InstanceUseId
	if len(instanceUseIds) == 0 {
		return response, fmt.Errorf("请选择云机")
	}
	instanceUseModel := resources.InstanceUses{}
	instanceUsesList, err := instanceUseModel.GetListByIds(db, instanceUseIds)
	if err != nil {
		glog.Errorf("get instance uses failed:err %v", err)
		return response, err
	}

	packageInfo := products.ProductPackages{Id: params.PackageId}
	err = packageInfo.GetById(db)
	if err != nil {
		glog.Errorf("get product package info failed:err %v", err)
		return response, err
	}
	feeTotal := float64(len(instanceUsesList)) * packageInfo.Price
	orderGenerator := NewBaseOrderGenerator("RENEW")
	tradeNo := orderGenerator.Generate()
	ProductPackageInfo := products.ProductPackages{Id: params.PackageId}
	err = ProductPackageInfo.GetById(db)
	if err != nil {
		glog.Errorf("get product package info failed:err %v", err)
		return response, err
	}
	order := &orders.Orders{
		TradeNo: tradeNo,
		Amount:  feeTotal,
		//Remark:        params.Remark,
		TransType:     int(orders.TransType_Recharge),
		UserId:        userId,
		Status:        int(orders.OrderStatus_Pending),
		CreatedAt:     time.Now(),
		UpdatedAt:     time.Now(),
		PaymentSource: params.PaymentSource,
		ClientIp:      params.ClientIp,
		DeviceInfo:    params.DeviceInfo,
		OrderType:     int(orders.OrderTypeRenew),
		ProductId:     packageInfo.ProductId,
		PackageId:     params.PackageId,
		//OrderType: int(orders.OrderStatus_Pending),
		//Quantity: params.Quantity,
	}
	err = db.Transaction(func(tx *gorm.DB) error {
		err = order.Create(db)
		if err != nil {
			glog.Errorf("create order failed:err %v", err)
			return err
		}
		for _, instanceUse := range instanceUsesList {
			if instanceUse.Status != int(resources.InstanceUseStatusUsing) {
				glog.Errorf("%s不在使用状态", instanceUse.InstanceName)
				return fmt.Errorf("%s不在使用状态", instanceUse.InstanceName)
			}
			if instanceUse.UserId != userId {
				glog.Errorf("instance use is using:err %v", err)
				return fmt.Errorf("云机编号错误")
			}
			instanceUsesNow := resources.InstanceUses{InstanceId: instanceUse.InstanceId}
			err = instanceUsesNow.GetUsingByInstanceId(db)
			if err != nil {
				if err != gorm.ErrRecordNotFound {
					glog.Errorf("get instance use failed:err %v", err)
					return err
				} else {
					if instanceUsesNow.Id != 0 && instanceUsesNow.UserId != userId {
						glog.Errorf("instance use is using:err %v", err)
						return fmt.Errorf("该云机已出售")
					}
				}

			}

			//	//instanceModel := instanceUseModel.Instances
			actualStartTime := time.Now()
			if instanceUsesNow.StartTime.Unix() > 0 {
				actualStartTime = instanceUsesNow.StartTime
			}
			instanceUses := resources.InstanceUses{
				//InstanceId: params.InstanceId,
				InstanceId:      instanceUse.InstanceId,
				OrderId:         order.Id,
				StartTime:       instanceUsesNow.ExpireTime,
				ActualStartTime: actualStartTime,
				ExpireTime:      instanceUsesNow.ExpireTime.Add(time.Duration(ProductPackageInfo.Duration) * time.Hour * 24),
				Status:          int(resources.InstanceUseStatusPending),
				UserId:          userId,
				Image:           "android/redroid",
				ImageTag:        instanceUse.ImageTag,
				PrewInstanceId:  instanceUsesNow.Id,
				IsRenew:         1,
				AutoRenew:       instanceUsesNow.AutoRenew,
				InstanceName:    instanceUsesNow.InstanceName,
			}
			err = instanceUses.Create(tx)
			if err != nil {
				glog.Errorf("create instance use failed:err %v", err)
				return err
			}
			instanceModel := instanceUse.Instances
			//instanceModel.Status = int(resources.InstanceUseStatusUsing)
			err = instanceModel.UpdatePartFields(tx, map[string]interface{}{"status": int(resources.InstanceUseStatusUsing)})
			if err != nil {
				glog.Errorf("update instance use failed:err %v", err)
				return err
			}
		}
		return nil
	})
	if config.Config == nil {
		config.InitConfig()
	}
	Config := config.Config
	domain := os.Getenv("DOMAIN")
	if domain == "" {
		domain = "https://clp.jtcloud.icu"
	}
	var payment payment2.UniCreateOrder
	switch params.PaymentSource {
	case "wechat":
		payment = &payment2.WechatPay{
			Amount:      feeTotal * 100, //OrderModel.Amount * 100, //TODO Amount*100,
			Description: "购买云机",
			OutTradeNo:  tradeNo,
			//Remark:          params.Remark,
			WechatPayConfig: Config.WechatPay,
		}
	case "alipay":
		payment = &payment2.Alipay{
			Amount:      feeTotal,
			Description: "购买云机",
			OutTradeNo:  tradeNo,
			//Remark:      params.Remark,
			Subject: "云机购买",
			Url:     domain + "/purches",
		}
	case "balance":
		payment = &payment2.Balance{
			Amount:  feeTotal,
			OrderId: order.Id,
			UserId:  userId,
		}
	}
	result, err := payment.Payment()
	if err != nil {
		glog.Errorf("payment failed:err %v", err)
		return response, err
	}
	resultType := payment.GetResultType()
	response = CreateOrderResp{
		Data:       result,
		ResultType: string(resultType),
		TradeNo:    tradeNo,
		OrderId:    order.Id,
	}

	return response, nil
}
